package com.ruoyi.water.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.water.domain.Element;
import com.ruoyi.water.domain.Homepage;
import com.ruoyi.water.domain.MeterAnalyse;
import com.ruoyi.water.mapper.ElementMapper;
import com.ruoyi.water.mapper.HomepageMapper;
import com.ruoyi.water.mapper.MeterAnalyseMapper;
import com.ruoyi.water.service.IHomepageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.lang.Console.log;

/**
 * 首页水相关 Service 实现类
 */
@Service
public class HomepageServiceImpl extends ServiceImpl<HomepageMapper, Homepage> implements IHomepageService {

    private static final Logger log = LoggerFactory.getLogger(HomepageServiceImpl.class);

    @Autowired
    private MeterAnalyseMapper meterAnalyseMapper;

    @Autowired
    private ElementMapper elementMapper;

    /**
     * 对外提供的计算用水趋势的公共方法
     * 新增：核心步骤异常时捕获，跳过当前步骤不中断整体流程
     */
    @Override
    public void calculateHomepage() {
        try {
            usageTrendCalculate();
        } catch (Exception e) {
            log.error("用水趋势计算执行失败，跳过该步骤", e);
        }
        try {
            rankCalculate();
        } catch (Exception e) {
            log.error("排名计算执行失败，跳过该步骤", e);
        }
        try {
            totalLeakageCalculate();
        } catch (Exception e) {
            log.error("漏耗计算执行失败，跳过该步骤", e);
        }
    }

    /**
     * 计算用水趋势并保存结果到数据库（核心内部方法）
     * 【关键修改】：删除提前批量清理历史数据的逻辑，改为"计算出新高后更新旧数据"
     */
    @Transactional(rollbackFor = Exception.class)
    public void usageTrendCalculate() {
        int currentYear = LocalDate.now().getYear();
        // 移除原clearExistingData(currentYear)调用：避免未计算出结果就删除旧数据

        Map<String, Double> dailyUsageMap = calculateDailyUsage(currentYear);
        Map<Integer, Double> monthlyUsageMap = calculateMonthlyUsage(dailyUsageMap, currentYear);
        double currentYearTotalUsage = calculateYearlyUsage(monthlyUsageMap);

        try {
            calculateAndSaveBiases(dailyUsageMap, monthlyUsageMap, currentYearTotalUsage, currentYear);
        } catch (Exception e) {
            log.error("偏差计算执行失败，跳过该步骤", e);
        }

        try {
            saveHomepageData("yearUsage_" + currentYear, currentYearTotalUsage, 5, null);
        } catch (Exception e) {
            log.error("保存年度总用量数据失败，跳过该条", e);
        }
    }

    // -------------------------- 排名计算核心方法（修改：昨天数据查询异常处理） --------------------------
    private void rankCalculate() {
        calculateYesterdayUsageRank();
        calculateMonthlyUsageRank();
        calculateYesterdayMinValRank();
    }

    /**
     * 功能1：昨天用量排名（修改：查询异常捕获+单条保存异常跳过）
     */
    private void calculateYesterdayUsageRank() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        List<MeterAnalyse> analyseList;

        // 1. 查询昨天数据：捕获异常，失败则跳过整个排名计算
        try {
            QueryWrapper<MeterAnalyse> wrapper = new QueryWrapper<>();
            wrapper.eq("analyseDate", yesterday);
            analyseList = meterAnalyseMapper.selectList(wrapper);
        } catch (RuntimeException e) {
            log.warn("查询{}的用量排名数据失败，跳过该排名计算", yesterday, e);
            return;
        }

        // 2. 排序（空列表会直接跳过循环，无异常）
        List<MeterAnalyse> sortedList = analyseList.stream()
                .sorted((a, b) -> Double.compare(
                        Optional.ofNullable(b.getTodayUsage()).orElse(0.0),
                        Optional.ofNullable(a.getTodayUsage()).orElse(0.0)
                ))
                .limit(6)
                .collect(Collectors.toList());

        // 3. 保存数据：单条失败跳过，不影响其他条（仅计算出排名后才处理旧数据）
        for (int i = 0; i < sortedList.size(); i++) {
            try {
                MeterAnalyse analyse = sortedList.get(i);
                String valueCode = "usageTop" + (i + 1);
                double usage = Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
                String meterName = Optional.ofNullable(analyse.getMeterName()).orElse("未知仪表");
                saveHomepageData(valueCode, usage, 3, meterName);
            } catch (RuntimeException e) {
                log.warn("保存昨天用量排名第{}条数据失败，跳过该条", i + 1, e);
                continue;
            }
        }
    }

    /**
     * 功能2：本月用量排名（无昨天数据，仅单条保存异常处理）
     */
    private void calculateMonthlyUsageRank() {
        YearMonth currentMonth = YearMonth.now();
        LocalDate monthStart = currentMonth.atDay(1);
        LocalDate monthEnd = currentMonth.atEndOfMonth();
        List<MeterAnalyse> analyseList;

        try {
            QueryWrapper<MeterAnalyse> wrapper = new QueryWrapper<>();
            wrapper.between("analyseDate", monthStart, monthEnd);
            analyseList = meterAnalyseMapper.selectList(wrapper);
        } catch (RuntimeException e) {
            log.warn("查询本月用量排名数据失败，跳过该排名计算", e);
            return;
        }

        Map<String, MeterRankVO> meterUsageMap = new HashMap<>();
        for (MeterAnalyse analyse : analyseList) {
            try {
                String meterId = String.valueOf(Optional.ofNullable(analyse.getMeterId()).orElse(-1));
                double usage = Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
                String meterName = Optional.ofNullable(analyse.getMeterName()).orElse("未知仪表");

                if (meterUsageMap.containsKey(meterId)) {
                    meterUsageMap.get(meterId).setTotalUsage(meterUsageMap.get(meterId).getTotalUsage() + usage);
                } else {
                    MeterRankVO vo = new MeterRankVO();
                    vo.setTotalUsage(usage);
                    vo.setMeterName(meterName);
                    meterUsageMap.put(meterId, vo);
                }
            } catch (RuntimeException e) {
                log.warn("处理单条本月计量数据失败，跳过该条", e);
                continue;
            }
        }

        List<MeterRankVO> sortedVOList = meterUsageMap.values().stream()
                .sorted((a, b) -> Double.compare(b.getTotalUsage(), a.getTotalUsage()))
                .limit(6)
                .collect(Collectors.toList());

        for (int i = 0; i < sortedVOList.size(); i++) {
            try {
                MeterRankVO vo = sortedVOList.get(i);
                String valueCode = "monthUsageTop" + (i + 1);
                saveHomepageData(valueCode, vo.getTotalUsage(), 3, vo.getMeterName());
            } catch (RuntimeException e) {
                log.warn("保存本月用量排名第{}条数据失败，跳过该条", i + 1, e);
                continue;
            }
        }
    }

    /**
     * 功能3：昨天最小流量排名（修改：查询异常捕获+单条保存异常跳过）
     */
    private void calculateYesterdayMinValRank() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        List<MeterAnalyse> analyseList;

        // 1. 查询昨天数据：捕获异常，失败则跳过
        try {
            QueryWrapper<MeterAnalyse> wrapper = new QueryWrapper<>();
            wrapper.eq("analyseDate", yesterday);
            analyseList = meterAnalyseMapper.selectList(wrapper);
        } catch (RuntimeException e) {
            log.warn("查询{}的最小流量排名数据失败，跳过该排名计算", yesterday, e);
            return;
        }

        // 2. 排序（空列表无影响）
        List<MeterAnalyse> sortedList = analyseList.stream()
                .sorted((a, b) -> Double.compare(
                        Optional.ofNullable(b.getTodayMinVal()).orElse(0.0),
                        Optional.ofNullable(a.getTodayMinVal()).orElse(0.0)
                ))
                .limit(6)
                .collect(Collectors.toList());

        // 3. 保存：单条失败跳过（仅计算出排名后才处理旧数据）
        for (int i = 0; i < sortedList.size(); i++) {
            try {
                MeterAnalyse analyse = sortedList.get(i);
                String valueCode = "minValTop" + (i + 1);
                double minVal = Optional.ofNullable(analyse.getTodayMinVal()).orElse(0.0);
                String meterName = Optional.ofNullable(analyse.getMeterName()).orElse("未知仪表");
                saveHomepageData(valueCode, minVal, 4, meterName);
            } catch (RuntimeException e) {
                log.warn("保存昨天最小流量排名第{}条数据失败，跳过该条", i + 1, e);
                continue;
            }
        }
    }

    // -------------------------- 漏耗计算核心方法（修改：日期转换异常处理） --------------------------
    private void totalLeakageCalculate() {
        int currentYear = LocalDate.now().getYear();
        Map<String, Integer> elementLevelMap = getElementLevelMap();
        if (elementLevelMap.isEmpty()) {
            log.warn("未查询到Element表数据，漏耗计算终止");
            return;
        }

        LocalDate yearStart = LocalDate.of(currentYear, 1, 1);
        LocalDate yearEnd = LocalDate.of(currentYear, 12, 31);
        List<MeterAnalyse> yearMeterAnalyses = getMeterAnalyseByDateRange(yearStart, yearEnd);
        if (yearMeterAnalyses.isEmpty()) {
            log.warn("未查询到{}年MeterAnalyse数据，漏耗计算终止", currentYear);
            return;
        }

        try {
            calculateAndSaveYearLeakage(yearMeterAnalyses, elementLevelMap);
        } catch (Exception e) {
            log.error("本年漏耗计算失败，跳过该步骤", e);
        }
        try {
            calculateAndSaveMonthLeakage(yearMeterAnalyses, elementLevelMap);
        } catch (Exception e) {
            log.error("本月漏耗计算失败，跳过该步骤", e);
        }
    }

    /**
     * 辅助方法1：查询Element表，返回【element.id-elemLevel】映射（过滤无效空值）
     */
    private Map<String, Integer> getElementLevelMap() {
        try {
            QueryWrapper<Element> wrapper = new QueryWrapper<>();
            wrapper.select("id", "elemLevel"); // 只查询必要字段
            List<Element> elements = elementMapper.selectList(wrapper);

            // 关键修改1：过滤elemLevel为null的无效记录，避免toMap时抛NPE
            Map<String, Integer> levelMap = elements.stream()
                    .filter(element -> element.getElemLevel() != null) // 过滤value为null的记录
                    .collect(Collectors.toMap(
                            element -> String.valueOf(element.getId()), // id转String（避免Long/Integer类型冲突）
                            Element::getElemLevel, // 此时value已确保非null
                            (oldVal, newVal) -> newVal // 若存在重复id（极低概率），取最新值
                    ));

            // 关键修改2：区分“无数据”和“无有效数据”，日志更精准
            if (levelMap.isEmpty()) {
                log.warn("查询到Element表数据，但均为elemLevel=null的无效数据，返回空映射");
                return Collections.emptyMap();
            }
            return levelMap;

        } catch (RuntimeException e) {
            // 关键修改3：修正日志描述，明确是“转换Map失败”而非“查询失败”
            log.error("Element表数据查询后转换为Map失败（非查询失败），返回空映射", e);
            return Collections.emptyMap();
        }
    }

    private List<MeterAnalyse> getMeterAnalyseByDateRange(LocalDate startDate, LocalDate endDate) {
        try {
            QueryWrapper<MeterAnalyse> wrapper = new QueryWrapper<>();
            wrapper.between("analyseDate", startDate, endDate)
                    .select("meterId", "todayUsage", "analyseDate");
            return meterAnalyseMapper.selectList(wrapper);
        } catch (RuntimeException e) {
            log.warn("查询{}至{}的计量数据失败，返回空列表", startDate, endDate, e);
            return Collections.emptyList();
        }
    }

    private void calculateAndSaveYearLeakage(List<MeterAnalyse> meterAnalyses, Map<String, Integer> elementLevelMap) {
        double level1Total = 0.0;
        double level2Total = 0.0;

        for (MeterAnalyse analyse : meterAnalyses) {
            try {
                String meterIdStr = String.valueOf(Optional.ofNullable(analyse.getMeterId()).orElse(-1));
                Integer elemLevel = elementLevelMap.get(meterIdStr);
                if (elemLevel == null) continue;

                double todayUsage = Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
                if (elemLevel == 1) level1Total += todayUsage;
                else if (elemLevel == 2) level2Total += todayUsage;
            } catch (RuntimeException e) {
                log.warn("处理单条本年漏耗数据失败，跳过该条", e);
                continue;
            }
        }

        try {
            // 仅计算出level1Total后，才处理yearLeakageLevel_1的旧数据
            saveHomepageData("yearLeakageLevel_1", level1Total, 2, null);
        } catch (Exception e) {
            log.warn("保存本年漏耗数据（level1）失败，跳过该条", e);
        }
        try {
            // 仅计算出level2Total后，才处理yearLeakageLevel_2的旧数据
            saveHomepageData("yearLeakageLevel_2", level2Total, 2, null);
        } catch (Exception e) {
            log.warn("保存本年漏耗数据（level2）失败，跳过该条", e);
        }
    }

    /**
     * 辅助方法4：计算本月漏耗（修改：日期转换单条异常跳过）
     */
    private void calculateAndSaveMonthLeakage(List<MeterAnalyse> yearMeterAnalyses, Map<String, Integer> elementLevelMap) {
        YearMonth currentMonth = YearMonth.now();
        LocalDate monthStart = currentMonth.atDay(1);
        LocalDate monthEnd = currentMonth.atEndOfMonth();

        // 日期转换：单条数据异常时过滤掉，不中断整个流
        List<MeterAnalyse> monthMeterAnalyses = yearMeterAnalyses.stream()
                .filter(analyse -> {
                    try {
                        java.util.Date utilDate = analyse.getAnalyseDate();
                        if (utilDate == null) {
                            log.debug("计量数据analyseDate为null，跳过该条");
                            return false;
                        }
                        LocalDate analyseDate = utilDate.toInstant()
                                .atZone(ZoneId.systemDefault())
                                .toLocalDate();
                        return !analyseDate.isBefore(monthStart) && !analyseDate.isAfter(monthEnd);
                    } catch (Exception e) {
                        log.warn("转换计量数据日期失败，跳过该条", e);
                        return false;
                    }
                })
                .collect(Collectors.toList());

        double level1Total = 0.0;
        double level2Total = 0.0;
        for (MeterAnalyse analyse : monthMeterAnalyses) {
            try {
                String meterIdStr = String.valueOf(Optional.ofNullable(analyse.getMeterId()).orElse(-1));
                Integer elemLevel = elementLevelMap.get(meterIdStr);
                if (elemLevel == null) continue;

                double todayUsage = Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
                if (elemLevel == 1) level1Total += todayUsage;
                else if (elemLevel == 2) level2Total += todayUsage;
            } catch (RuntimeException e) {
                log.warn("处理单条本月漏耗数据失败，跳过该条", e);
                continue;
            }
        }

        try {
            // 仅计算出本月level1Total后，才处理monthLeakageLevel_1的旧数据
            saveHomepageData("monthLeakageLevel_1", level1Total, 2, null);
        } catch (Exception e) {
            log.warn("保存本月漏耗数据（level1）失败，跳过该条", e);
        }
        try {
            // 仅计算出本月level2Total后，才处理monthLeakageLevel_2的旧数据
            saveHomepageData("monthLeakageLevel_2", level2Total, 2, null);
        } catch (Exception e) {
            log.warn("保存本月漏耗数据（level2）失败，跳过该条", e);
        }
    }

    /**
     * 保存首页数据：仅在计算出新高后调用，自动处理旧数据（有则更新、无则插入）
     * 符合需求：仅当value已确定（计算完成），才会覆盖/插入数据，旧数据不会被提前删除
     */
    private void saveHomepageData(String valueCode, double value, int valueType, String key) {
        Homepage existingData = baseMapper.selectById(valueCode);
        Homepage homepage = new Homepage();
        homepage.setValueCode(valueCode);
        homepage.setValue(value);
        homepage.setValueType(valueType);
        homepage.setKey(key);
        homepage.setRecordTime(new Timestamp(System.currentTimeMillis()));

        if (existingData != null) {
            // 计算出新高后，更新旧数据（相当于"删除旧值+插入新值"的高效实现）
            baseMapper.updateById(homepage);
        } else {
            baseMapper.insert(homepage);
        }
    }

    // -------------------------- 原有辅助方法（修改：单条保存异常跳过） --------------------------
    private Map<String, Double> calculateDailyUsage(int year) {
        Map<String, Double> dailyUsageMap = new HashMap<>();
        LocalDate startDate = LocalDate.of(year, 1, 1);
        LocalDate endDate = LocalDate.of(year, 12, 31);
        YearMonth currentYearMonth = YearMonth.now();
        YearMonth lastYearMonth = currentYearMonth.minusMonths(1);

        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            double totalUsage = 0.0;
            try {
                QueryWrapper<MeterAnalyse> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("analyseDate", currentDate);
                List<MeterAnalyse> list = meterAnalyseMapper.selectList(queryWrapper);
                for (MeterAnalyse analyse : list) {
                    totalUsage += Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
                }
            } catch (RuntimeException e) {
                log.warn("查询{}的日用量数据失败，使用0.0参与计算", currentDate, e);
                totalUsage = 0.0;
            }
            dailyUsageMap.put(currentDate.format(DateTimeFormatter.ISO_LOCAL_DATE), totalUsage);

            YearMonth dateYearMonth = YearMonth.from(currentDate);
            // 保存数据：仅计算出totalUsage后，才处理对应valueCode的旧数据
            if (dateYearMonth.equals(currentYearMonth) || dateYearMonth.equals(lastYearMonth)) {
                int dayOfMonth = currentDate.getDayOfMonth();
                String valueCode = dateYearMonth.equals(lastYearMonth)
                        ? "monthagoDayTotalUsage_" + dayOfMonth
                        : "dayTotalUsage_" + dayOfMonth;
                try {
                    saveHomepageData(valueCode, totalUsage, 5, null);
                } catch (RuntimeException e) {
                    log.warn("保存日用量数据（{}）失败，跳过该条", valueCode, e);
                }
            }

            currentDate = currentDate.plusDays(1);
        }
        return dailyUsageMap;
    }

    private Map<Integer, Double> calculateMonthlyUsage(Map<String, Double> dailyUsageMap, int year) {
        Map<Integer, Double> monthlyUsageMap = new HashMap<>();
        for (int month = 1; month <= 12; month++) {
            YearMonth yearMonth = YearMonth.of(year, month);
            LocalDate startDate = yearMonth.atDay(1);
            LocalDate endDate = yearMonth.atEndOfMonth();
            double monthlyTotal = 0.0;

            LocalDate currentDate = startDate;
            while (!currentDate.isAfter(endDate)) {
                monthlyTotal += dailyUsageMap.getOrDefault(currentDate.format(DateTimeFormatter.ISO_LOCAL_DATE), 0.0);
                currentDate = currentDate.plusDays(1);
            }

            monthlyUsageMap.put(month, monthlyTotal);
            // 保存数据：仅计算出monthlyTotal后，才处理monthUsage_xx的旧数据
            try {
                saveHomepageData("monthUsage_" + month, monthlyTotal, 5, null);
            } catch (RuntimeException e) {
                log.warn("保存月用量数据（monthUsage_{}）失败，跳过该条", month, e);
                continue;
            }
        }
        return monthlyUsageMap;
    }

    private double calculateYearlyUsage(Map<Integer, Double> monthlyUsageMap) {
        double total = 0.0;
        for (double monthUsage : monthlyUsageMap.values()) {
            total += monthUsage;
        }
        return total;
    }

    /**
     * 偏差计算（修改：昨天数据异常时日志+跳过）
     */
    private void calculateAndSaveBiases(Map<String, Double> dailyUsageMap,
                                        Map<Integer, Double> monthlyUsageMap,
                                        double currentYearTotalUsage, int currentYear) {
        try {
            calculateYesterdayBiases(dailyUsageMap, currentYear);
        } catch (Exception e) {
            log.error("昨天偏差计算失败，跳过该步骤", e);
        }
        try {
            calculateCurrentMonthBiases(monthlyUsageMap, LocalDate.now().getMonthValue(), currentYear);
        } catch (Exception e) {
            log.error("本月偏差计算失败，跳过该步骤", e);
        }
        try {
            calculateYearlyBias(currentYearTotalUsage, currentYear);
        } catch (Exception e) {
            log.error("年度偏差计算失败，跳过该步骤", e);
        }
    }

    private void calculateYesterdayBiases(Map<String, Double> dailyUsageMap, int currentYear) {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        if (yesterday.getYear() != currentYear) {
            log.debug("昨天不属于当前年份（{}），跳过昨天偏差计算", currentYear);
            return;
        }

        // 昨天数据为空时日志提示，不中断
        String yesterdayStr = yesterday.format(DateTimeFormatter.ISO_LOCAL_DATE);
        double yesterdayUsage = dailyUsageMap.getOrDefault(yesterdayStr, 0.0);
        if (yesterdayUsage == 0.0) {
            log.debug("{}的日用量数据为空，使用0.0参与偏差计算", yesterday);
        }

        LocalDate lastMonthSameDay = yesterday.minusMonths(1);
        LocalDate lastYearSameDay = yesterday.minusYears(1);
        double lastMonthSameDayUsage = getMeterAnalyseTotalByDate(lastMonthSameDay);
        double lastYearSameDayUsage = getMeterAnalyseTotalByDate(lastYearSameDay);

        try {
            // 仅计算出dayMonthBias后，才处理旧数据
            saveHomepageData("dayMonthBias", calculatePercentageBias(yesterdayUsage, lastMonthSameDayUsage), 1, null);
        } catch (RuntimeException e) {
            log.warn("保存昨天月度偏差数据失败，跳过该条", e);
        }
        try {
            // 仅计算出dayYearBias后，才处理旧数据
            saveHomepageData("dayYearBias", calculatePercentageBias(yesterdayUsage, lastYearSameDayUsage), 1, null);
        } catch (RuntimeException e) {
            log.warn("保存昨天年度偏差数据失败，跳过该条", e);
        }
    }

    private void calculateCurrentMonthBiases(Map<Integer, Double> monthlyUsageMap, int currentMonth, int currentYear) {
        double currentMonthUsage = monthlyUsageMap.getOrDefault(currentMonth, 0.0);
        int lastMonth = currentMonth - 1;
        int lastMonthYear = currentYear;
        if (lastMonth < 1) {
            lastMonth = 12;
            lastMonthYear = currentYear - 1;
        }

        double lastMonthUsage = getMonthlyUsageFromMeterAnalyse(lastMonthYear, lastMonth);
        double lastYearSameMonthUsage = getMonthlyUsageFromMeterAnalyse(currentYear - 1, currentMonth);

        try {
            // 仅计算出monthMonthBias后，才处理旧数据
            saveHomepageData("monthMonthBias", calculatePercentageBias(currentMonthUsage, lastMonthUsage), 1, null);
        } catch (RuntimeException e) {
            log.warn("保存本月月度偏差数据失败，跳过该条", e);
        }
        try {
            // 仅计算出monthYearBias后，才处理旧数据
            saveHomepageData("monthYearBias", calculatePercentageBias(currentMonthUsage, lastYearSameMonthUsage), 1, null);
        } catch (RuntimeException e) {
            log.warn("保存本月年度偏差数据失败，跳过该条", e);
        }
    }

    private void calculateYearlyBias(double currentYearTotalUsage, int currentYear) {
        QueryWrapper<Homepage> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("valueType", 5)
                .eq("valueCode", "yearUsage_" + (currentYear - 1));
        Homepage lastYearData;
        try {
            lastYearData = baseMapper.selectOne(queryWrapper);
        } catch (RuntimeException e) {
            log.warn("查询去年年度用量数据失败，使用0.0参与计算", e);
            lastYearData = null;
        }

        double lastYearTotalUsage = lastYearData != null ?
                Optional.ofNullable(lastYearData.getValue()).orElse(0.0) : 0.0;

        try {
            // 仅计算出yearYearBias后，才处理旧数据
            saveHomepageData("yearYearBias", calculatePercentageBias(currentYearTotalUsage, lastYearTotalUsage), 1, null);
        } catch (RuntimeException e) {
            log.warn("保存年度偏差数据失败，跳过该条", e);
        }
    }

    /**
     * 辅助方法：获取指定日期总用量（修改：异常时返回0.0）
     */
    private double getMeterAnalyseTotalByDate(LocalDate date) {
        List<MeterAnalyse> list;
        try {
            QueryWrapper<MeterAnalyse> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("analyseDate", date);
            list = meterAnalyseMapper.selectList(queryWrapper);
        } catch (RuntimeException e) {
            log.warn("查询{}的计量总用量数据失败，返回0.0", date, e);
            return 0.0;
        }

        double total = 0.0;
        for (MeterAnalyse analyse : list) {
            try {
                total += Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
            } catch (RuntimeException e) {
                log.warn("处理单条计量数据用量失败，跳过该条", e);
                continue;
            }
        }
        return total;
    }

    private double getMonthlyUsageFromMeterAnalyse(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate startDate = yearMonth.atDay(1);
        LocalDate endDate = yearMonth.atEndOfMonth();
        List<MeterAnalyse> list;

        try {
            QueryWrapper<MeterAnalyse> queryWrapper = new QueryWrapper<>();
            queryWrapper.between("analyseDate", startDate, endDate);
            list = meterAnalyseMapper.selectList(queryWrapper);
        } catch (RuntimeException e) {
            log.warn("查询{}年{}月计量总用量数据失败，返回0.0", year, month, e);
            return 0.0;
        }

        double total = 0.0;
        for (MeterAnalyse analyse : list) {
            try {
                total += Optional.ofNullable(analyse.getTodayUsage()).orElse(0.0);
            } catch (RuntimeException e) {
                log.warn("处理单条月度计量数据用量失败，跳过该条", e);
                continue;
            }
        }
        return total;
    }

    private double calculatePercentageBias(double currentValue, double compareValue) {
        if (compareValue == 0) {
            return 0;
        }
        return new BigDecimal((currentValue - compareValue) / compareValue * 100)
                .setScale(2, RoundingMode.HALF_UP)
                .doubleValue();
    }

    /**
     * 内部VO：用于本月用量分组排名
     */
    private static class MeterRankVO {
        private double totalUsage;
        private String meterName;

        public double getTotalUsage() {
            return totalUsage;
        }

        public void setTotalUsage(double totalUsage) {
            this.totalUsage = totalUsage;
        }

        public String getMeterName() {
            return meterName;
        }

        public void setMeterName(String meterName) {
            this.meterName = meterName;
        }
    }
}